package com.tellus.util;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.impl.CriteriaImpl;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

public class GenericTellixDaoImpl<E, PK extends Serializable> extends
HibernateDaoSupport implements GenericTellixDao<E, PK> {
	
	protected Class<E> tipo;

	@SuppressWarnings("unchecked")
	public GenericTellixDaoImpl() {
		// super();
		ParameterizedType genericSuperclass = (ParameterizedType) getClass()
				.getGenericSuperclass();
		this.tipo = (Class<E>) genericSuperclass.getActualTypeArguments()[0];

	}

	@Transactional(propagation = Propagation.REQUIRED)
	public E save(E entity) {
		getHibernateTemplate().saveOrUpdate(entity);
		return entity;
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public E findById(PK id) {
		return getHibernateTemplate().get(tipo, id);
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public E update(E entity) {
		getHibernateTemplate().update(entity);
		return entity;
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(E entity) {
		getHibernateTemplate().delete(entity);
	}

	@Transactional(propagation = Propagation.REQUIRED)
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> getList(final CriteriaImpl criteriaImpl) {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						criteriaImpl.setSession((SessionImplementor) session);
						criteriaImpl.setMaxResults(200);

						return criteriaImpl.list();
					}

				});
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public E obtenerPorCodigo(final String codigo) {

		return this.getHibernateTemplate().execute(new HibernateCallback<E>() {

			@SuppressWarnings("unchecked")
			public E doInHibernate(Session session) {

				Criteria criteria = session.createCriteria(tipo);

				criteria.add(Restrictions.eq("codigo", codigo));

				return (E) criteria.uniqueResult();
			}

		});
	}

	// @Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> obtenerCreadosHoy() {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						Criteria criteria = session.createCriteria(tipo);

						Date hoy = new Date();

						Calendar fechaInicio = Calendar.getInstance();
						fechaInicio.setTime(hoy);
						fechaInicio.set(Calendar.HOUR_OF_DAY, 0);
						fechaInicio.set(Calendar.MINUTE, 0);
						fechaInicio.set(Calendar.SECOND, 0);

						criteria.add(Restrictions.ge("fechaCreacion",
								fechaInicio.getTime()));

						Calendar fechaFin = Calendar.getInstance();
						fechaFin.setTime(hoy);
						fechaFin.set(Calendar.HOUR_OF_DAY, 23);
						fechaFin.set(Calendar.MINUTE, 59);
						fechaFin.set(Calendar.SECOND, 59);
						criteria.add(Restrictions.le("fechaCreacion",
								fechaFin.getTime()));

						criteria.addOrder(Order.desc("id"));

						List lista = criteria.list();

						return lista;
					}

				});
	}

	// @Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> obtenerActualizadosHoy() {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						Criteria criteria = session.createCriteria(tipo);

						Date hoy = new Date();

						Calendar fechaInicio = Calendar.getInstance();
						fechaInicio.setTime(hoy);
						fechaInicio.set(Calendar.HOUR_OF_DAY, 0);
						fechaInicio.set(Calendar.MINUTE, 0);
						fechaInicio.set(Calendar.SECOND, 0);

						criteria.add(Restrictions.ge("fechaActualizacion",
								fechaInicio.getTime()));

						Calendar fechaFin = Calendar.getInstance();
						fechaFin.setTime(hoy);
						fechaFin.set(Calendar.HOUR_OF_DAY, 23);
						fechaFin.set(Calendar.MINUTE, 59);
						fechaFin.set(Calendar.SECOND, 59);
						criteria.add(Restrictions.le("fechaActualizacion",
								fechaFin.getTime()));

						criteria.addOrder(Order.desc("id"));

						List lista = criteria.list();

						return lista;
					}

				});
	}

	// @Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> obtenerActivos() {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						Criteria criteria = session.createCriteria(tipo);

						criteria.add(Restrictions.eq("estado", true));

						List lista = criteria.list();

						return lista;
					}

				});
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> obtenerActivosOrdenado(final String order) {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						Criteria criteria = session.createCriteria(tipo);

						criteria.add(Restrictions.eq("estado", true));
						criteria.addOrder(Order.asc(order));

						List lista = criteria.list();

						return lista;
					}

				});
	}
	

	// @Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> obtenerPorFiltro(final Date fechaInicial,
			final Date fechaFinal, final Boolean estado) {

		return (List<E>) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					// @Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						Criteria criteria = session.createCriteria(tipo);

						Calendar fechaInicio = Calendar.getInstance();
						fechaInicio.setTime(fechaInicial);
						fechaInicio.set(Calendar.HOUR_OF_DAY, 0);
						fechaInicio.set(Calendar.MINUTE, 0);
						fechaInicio.set(Calendar.SECOND, 0);

						criteria.add(Restrictions.ge("fechaCreacion",
								fechaInicio.getTime()));

						Calendar fechaFin = Calendar.getInstance();
						fechaFin.setTime(fechaFinal);
						fechaFin.set(Calendar.HOUR_OF_DAY, 23);
						fechaFin.set(Calendar.MINUTE, 59);
						fechaFin.set(Calendar.SECOND, 59);
						criteria.add(Restrictions.le("fechaCreacion",
								fechaFin.getTime()));

						criteria.add(Restrictions.eq("estado", estado));

						criteria.addOrder(Order.desc("id"));

						List lista = criteria.list();

						return lista;
					}

				});
	}

}

